#ifndef SRC_BASE_COMPILERDETECTION_H_
#define SRC_BASE_COMPILERDETECTION_H_

#include "base/systemdetection.h"

/*
   The compiler, must be one of: (Q_CC_x)

     SYM      - Digital Mars C/C++ (used to be Symantec C++)
     MSVC     - Microsoft Visual C/C++, Intel C++ for Windows
     BOR      - Borland/Turbo C++
     WAT      - Watcom C++
     GNU      - GNU C++
     COMEAU   - Comeau C++
     EDG      - Edison Design Group C++
     OC       - CenterLine C++
     SUN      - Forte Developer, or Sun Studio C++
     MIPS     - MIPSpro C++
     DEC      - DEC C++
     HPACC    - HP aC++
     USLC     - SCO OUDK and UDK
     CDS      - Reliant C++
     KAI      - KAI C++
     INTEL    - Intel C++ for Linux, Intel C++ for Windows
     HIGHC    - MetaWare High C/C++
     PGI      - Portland Group C++
     GHS      - Green Hills Optimizing C++ Compilers
     RVCT     - ARM Realview Compiler Suite
     CLANG    - C++ front-end for the LLVM compiler


   Should be sorted most to least authoritative.
*/

/* Symantec C++ is now Digital Mars */
#if defined(__DMC__) || defined(__SC__)
# define CC_SYM
# if defined(__SC__)
#   define CC_SYM_VER (__SC__)
# endif

#elif defined(_MSC_VER)
# ifdef __clang__
#   define CC_CLANG
#   define CC_CLANG_VER ((__clang_major__ * 100) + __clang_minor__)
# endif
# define CC_MSVC
# define CC_MSVC_VER (_MSC_VER)
/* Intel C++ disguising as Visual C++: the `using' keyword avoids warnings */
# if defined(__INTEL_COMPILER)
#   define CC_INTEL
#   define CC_INTEL_VER (__INTEL_COMPILER)
# endif

#elif defined(__BORLANDC__) || defined(__TURBOC__)
# define CC_BOR
# if defined(__BORLANDC__)
#   define CC_BOR_VER (__BORLANDC__)
# endif
# if defined(__TURBOC__)
#   define CC_BOR_VER (__TURBOC__)
# endif

#elif defined(__WATCOMC__)
# define CC_WAT
# define CC_WAT_VER (__WATCOMC__)

/* ARM Realview Compiler Suite
   RVCT compiler also defines __EDG__ and __GNUC__ (if --gnu flag is given),
   so check for it before that */
#elif defined(__ARMCC__) || defined(__CC_ARM)
# define CC_RVCT
# if defined(__ARMCC__)
#   define CC_RVCT_VER (__ARMCC__)
# endif
# if defined(__CC_ARM)
#   define CC_RVCT_VER (__CC_ARM)
# endif

#elif defined(__GNUC__)
# define CC_GNU
# define CC_GNU_VER (__GNUC__ * 100 + __GNUC_MINOR__)
# if defined(__MINGW32__)
#   define CC_MINGW
#   define CC_MINGW_VER (__MINGW32__)
# endif
# if defined(__INTEL_COMPILER)
/* Intel C++ also masquerades as GCC */
#   define CC_INTEL
#   define CC_INTEL_VER (__INTEL_COMPILER)
#   ifdef __clang__
/* Intel C++ masquerades as Clang masquerading as GCC */
#     define CC_CLANG
#     define CC_CLANG_VER 305
#   endif
# elif defined(__clang__)
/* Clang also masquerades as GCC */
#   define CC_CLANG
#   if defined(__apple_build_version__)
#      /* http://en.wikipedia.org/wiki/Xcode#Toolchain_Versions */
#     if __apple_build_version__ >= 7000053
#       define CC_CLANG_VER 306
#     elif __apple_build_version__ >= 6000051
#       define CC_CLANG_VER 305
#     elif __apple_build_version__ >= 5030038
#       define CC_CLANG_VER 304
#     elif __apple_build_version__ >= 5000275
#       define CC_CLANG_VER 303
#     elif __apple_build_version__ >= 4250024
#       define CC_CLANG_VER 302
#     elif __apple_build_version__ >= 3180045
#       define CC_CLANG_VER 301
#     elif __apple_build_version__ >= 2111001
#       define CC_CLANG_VER 300
#     else
#       error "Unknown Apple Clang version"
#     endif
#   else
#      define CC_CLANG_VER ((__clang_major__ * 100) + __clang_minor__)
#   endif
# endif

/* IBM compiler versions are a bit messy. There are actually two products:
   the C product, and the C++ product. The C++ compiler is always packaged
   with the latest version of the C compiler. Version numbers do not always
   match. This little table (I'm not sure it's accurate) should be helpful:

   C++ product                C product

   C Set 3.1                  C Compiler 3.0
   ...                        ...
   C++ Compiler 3.6.6         C Compiler 4.3
   ...                        ...
   Visual Age C++ 4.0         ...
   ...                        ...
   Visual Age C++ 5.0         C Compiler 5.0
   ...                        ...
   Visual Age C++ 6.0         C Compiler 6.0

   Now:
   __xlC__    is the version of the C compiler in hexadecimal notation
              is only an approximation of the C++ compiler version
   __IBMCPP__ is the version of the C++ compiler in decimal notation
              but it is not defined on older compilers like C Set 3.1 */
#elif defined(__xlC__)
# define CC_XLC
# define CC_XLC_VER (__xlC__)

/* Older versions of DEC C++ do not define __EDG__ or __EDG - observed
   on DEC C++ V5.5-004. New versions do define  __EDG__ - observed on
   Compaq C++ V6.3-002.
   This compiler is different enough from other EDG compilers to handle
   it separately anyway. */
#elif defined(__DECCXX) || defined(__DECC)
# define CC_DEC
# define CC_DEC_VER (__DECCXX_VER)
/* Compaq C++ V6 compilers are EDG-based but I'm not sure about older
   DEC C++ V5 compilers. */
# if defined(__EDG__)
#   define CC_EDG
#   define CC_EDG_VER (__EDG__)
# endif

/* The Portland Group C++ compiler is based on EDG and does define __EDG__
   but the C compiler does not */
#elif defined(__PGI)
# define CC_PGI
# define CC_PGI_VER (__PGIC__)
# if defined(__EDG__)
#   define CC_EDG
#   define CC_EDG_VER (__EDG__)
# endif

/* Compilers with EDG front end are similar. To detect them we test:
   __EDG documented by SGI, observed on MIPSpro 7.3.1.1 and KAI C++ 4.0b
   __EDG__ documented in EDG online docs, observed on Compaq C++ V6.3-002
   and PGI C++ 5.2-4 */
#elif !defined(OS_HPUX) && (defined(__EDG) || defined(__EDG__))
# define CC_EDG
# if defined(__EDG)
#   define CC_EDG_VER (__EDG)
# endif
# if defined(__EDG__)
#   define CC_EDG_VER (__EDG__)
# endif

/* The Comeau compiler is based on EDG and does define __EDG__ */
# if defined(__COMO__)
#   define CC_COMEAU
#   define CC_COMEAU_VER (__COMO_VERSION__)

/* The `using' keyword was introduced to avoid KAI C++ warnings
   but it's now causing KAI C++ errors instead. The standard is
   unclear about the use of this keyword, and in practice every
   compiler is using its own set of rules. Forget it. */
# elif defined(__KCC)
#   define CC_KAI
#   define CC_KAI_VER (__KCC)

/* Using the `using' keyword avoids Intel C++ for Linux warnings */
# elif defined(__INTEL_COMPILER)
#   define CC_INTEL
#   define CC_INTEL_VER (__INTEL_COMPILER)

/* Uses CFront, make sure to read the manual how to tweak templates. */
# elif defined(__ghs)
#   define CC_GHS
#   define CC_GHS_VER (__GHS_VERSION_NUMBER)

# elif defined(__DCC__)
#   define CC_DIAB
#   define CC_DIAB_VER (__DCC__)

/* The UnixWare 7 UDK compiler is based on EDG and does define __EDG__ */
# elif defined(__USLC__) && defined(__SCO_VERSION__)
#   define CC_USLC
#   define CC_USLC_VER (__SCO_VERSION__)

/* Never tested! */
# elif defined(CENTERLINE_CLPP) || defined(OBJECTCENTER)
#   define CC_OC
#   if defined(CENTERLINE_CLPP)
#     define CC_OC_VER (CENTERLINE_CLPP)
#   endif
#   if defined(OBJECTCENTER)
#     define CC_OC_VER (OBJECTCENTER)
#   endif

/* CDS++ defines __EDG__ although this is not documented in the Reliant
   documentation. It also follows conventions like _BOOL and this documented */
# elif defined(sinix)
#   define CC_CDS
#   define CC_CDS_VER (sinix)

/* The MIPSpro compiler defines __EDG */
# elif defined(__sgi)
#   define CC_MIPS
#   if defined(_COMPILER_VERSION)
#      define CC_MIPS_VER (_COMPILER_VERSION)
#   endif
# endif

/* VxWorks' DIAB toolchain has an additional EDG type C++ compiler
   (see __DCC__ above). This one is for C mode files (__EDG is not defined) */
#elif defined(_DIAB_TOOL)
# define CC_DIAB
# define CC_DIAB_VER (_DIAB_TOOL)

/* Never tested! */
#elif defined(__HIGHC__)
# define CC_HIGHC
# define CC_HIGHC_VER (__HIGHC__)

#elif defined(__SUNPRO_CC) || defined(__SUNPRO_C)
# define CC_SUN
# define CC_SUN_VER (__SUNPRO_CC)

/* CDS++ does not seem to define __EDG__ or __EDG according to Reliant
   documentation but nevertheless uses EDG conventions like _BOOL */
#elif defined(sinix)
# define CC_EDG
# define CC_EDG_VER (sinix)
# define CC_CDS
# define CC_CDS_VER (sinix)

#elif defined(OS_HPUX)
/* __HP_aCC was not defined in first aCC releases */
# if defined(__HP_aCC) || __cplusplus >= 199707L
#   define CC_HPACC
#   define CC_HPACC_VER (__HP_aCC-0)
# endif

#else
# error "Not tested with this compiler - see http://www.qt-project.org/"
#endif

// Put after a variable that might not be used, to prevent compiler warnings:
//   int result ATTRIBUTE_UNUSED = DoSomething();
//   assert(result == 17);
#ifndef ATTRIBUTE_UNUSED
#if defined(CC_GNU) || defined(CC_CLANG)
#define ATTRIBUTE_UNUSED __attribute__((unused))
#else
#define ATTRIBUTE_UNUSED
#endif
#endif

// Annotate a function that will not return control flow to the caller.
#if defined(CC_MSVC)
#define NO_RETURN __declspec(noreturn)
#elif defined(CC_GNU)
#define NO_RETURN __attribute__((noreturn))
#else
#define NO_RETURN
#endif

#endif // SRC_BASE_COMPILERDETECTION_H_
